/*
 * @brief: v1.0 电量读取还没写。
 * @Author: TzzzT
 * @Date: 2022-03-06 01:08:44
 * @LastEditTime: 2023-05-03 13:46:45
 * @LastEditors: TzzzT
 */
#include "esp_err.h"
#include "hal/gpio_types.h"
#include "stdint.h"
#include "string.h"
#include "math.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "my_crc.h"
#include "RCS_fire.h"
#include "RCS_protocol.h"
#include "RCS_master.h"
#include "RCS_adc.h"

#include "esp_check.h"
#include "driver/rmt_tx.h"
#include "ir_rcs_encoder.h"

#include "ir_nec_encoder.h"

static const char *TAG = "IR_TAG";

extern rcs_mast_system_t rcsSystem;
////////////////////////////RMT TX////////////////////////////
extern QueueHandle_t xGameQueue; // 发射子弹后需要上报数据

#define RCS_RMT_TX_PIN GPIO_NUM_5
#define RCS_RMT_IR_RESOLUTION_HZ 1000000 // 1MHz resolution, 1 tick = 1us
#define RCS_RMT_IR_NEC_DECODE_MARGIN 200 // Tolerance for parsing RMT symbols into bit stream

static rmt_channel_handle_t tx_channel = NULL;
static rmt_tx_channel_config_t tx_channel_cfg = {
    .clk_src = RMT_CLK_SRC_DEFAULT,
    .resolution_hz = RCS_RMT_IR_RESOLUTION_HZ,
    .mem_block_symbols = 64, // amount of RMT symbols that the channel can store at a time
    .trans_queue_depth = 4,  // number of transactions that allowed to pending in the background, this example won't queue multiple transactions, so queue depth > 1 is sufficient
    .gpio_num = RCS_RMT_TX_PIN,
};
static rmt_carrier_config_t tx_carrier_cfg = {
    .duty_cycle = 0.33,
    .frequency_hz = 38000, // 38KHz
};
static rmt_transmit_config_t transmit_config = {
    .loop_count = 0, // no loop
};

static rmt_encoder_handle_t rcs_bullet_encoder = NULL;
void rcs_rmt_tx_init(void)
{
    ESP_LOGI(TAG, "create RMT TX channel");
    ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_channel_cfg, &tx_channel));
    ESP_LOGI(TAG, "modulate carrier to TX channel");
    ESP_ERROR_CHECK(rmt_apply_carrier(tx_channel, &tx_carrier_cfg));
    // this example won't send NEC frames in a loop
    ESP_LOGI(TAG, "install IR RCS encoder");
    ESP_ERROR_CHECK(rmt_new_rcs_bullet_encoder(&rcs_bullet_encoder));
    ESP_LOGI(TAG, "enable RMT TX and RX channels");
    ESP_ERROR_CHECK(rmt_enable(tx_channel));
}

////////////////////// APP /////////////////////////
static uint8_t bullet_send_array[BULLET_DATA_LEN] = {0};

static fix_bullet_t fix_bullet;

static void make_ble_fire_success_package(uint8_t *package, uint8_t package_len);

// 装入builder
void bullet_data_set(uint8_t is_in_fix_mode, player_t *player)
{
    if (is_in_fix_mode)
    {
        // fix mode only in offline mode.
        // team  = [0,1,2]
        fix_bullet.data.team = player->team;
        // 设置全为0，减少发送时长，接收端固定设置伤害为30.
        fix_bullet.data.damage = 0;
    }
    else
    {
        bullet_send_array[TEAM_ROOM] = (player->team * 10) + player->room;
        bullet_send_array[DAMAGE] = (player->damage) / 10;
        bullet_send_array[PLAYER_ID_1] = (player->id >> 16) & 0xFF;
        bullet_send_array[PLAYER_ID_2] = (player->id >> 8) & 0xFF;
        bullet_send_array[PLAYER_ID_3] = (player->id) & 0xFF;
        // ESP_LOGE(TAG, "fire-tx");
        // for (size_t i = 0; i < BULLET_DATA_LEN; i++)
        // {
        //     ESP_LOGE(TAG, "val[%d]: %02x", i, bullet_send_array[i]);
        // }
    }
}

bool fire(uint8_t is_in_fix_mode)
{
    esp_err_t ret;
    uint8_t *data_ptr = NULL;
    size_t data_len = 0;
    if (is_in_fix_mode)
    {
        data_ptr = &fix_bullet.array[0];
        data_len = sizeof(fix_bullet.array);
    }
    else
    {
        data_ptr = &bullet_send_array[0];
        data_len = sizeof(bullet_send_array);
    }
    ret = rmt_transmit(tx_channel, rcs_bullet_encoder, data_ptr, data_len, &transmit_config);
    if (ret == ESP_OK)
    {
        ESP_LOGI(TAG, "fire success");
        return true;
    }
    else
    {
        ESP_LOGE(TAG, "fire error");
        return false;
    }
}

void fire_success_handle(void)
{
    uint8_t package[11] = {0};
    make_ble_fire_success_package(package, 11);
    ESP_LOGI(TAG, "put fire_success_package in queue");
    if (xQueueSend(xGameQueue, package, pdMS_TO_TICKS(40)) != pdPASS)
    {
        ESP_LOGI(TAG, "queue full, try to connect ble server then send queue data to server.");
    }
}

static void make_ble_fire_success_package(uint8_t *package, uint8_t package_len)
{
    uint16_t data_head = 0;
    uint8_t data_len;

    data_len = PACKAGE_LEN_UPL_LEN;
    package[data_head] = data_len;
    package[data_head + 1] = PACKAGE_LEN_UPL;
    package[data_head + 2] = package_len;
    data_head += data_len;

    data_len = MESSAGE_TYPE_BATTERY_UPL_LEN;
    package[data_head] = data_len;
    package[data_head + 1] = MESSAGE_TYPE_BATTERY_UPL;
    package[data_head + 2] = CORE_FIRE_TYPE;
    package[data_head + 3] = rcsSystem.equip.core.battery;
    data_head += data_len;

    data_len = REMAIN_BULLET_NUM_UPL_LEN;
    package[data_head] = data_len;
    package[data_head + 1] = REMAIN_BULLET_NUM_UPL;
    package[data_head + 2] = (rcsSystem.game.player.bullet_nums & 0xFF00) >> 8;
    package[data_head + 3] = (rcsSystem.game.player.bullet_nums & 0x00FF);
    data_head += data_len;
    return;
}

///////////////////trigger///////////////////
bool is_pulling_trigger(void)
{
    bool ret = false;
    static int last_voltage = 0;
    int sub = 0;
    int voltage = rcs_adc_trigger_read();
    sub = voltage - last_voltage;
    if (voltage == 0 && abs(sub) <= 100)
    {
        // ESP_LOGI(TAG, "voltage == 0 && abs(sub): %d <= 100", abs(sub));
        return false;
    }
    ESP_LOGI(TAG, "voltage: %d last_voltage: %d sub: %d", voltage, last_voltage, sub);
    // if (voltage <= 150)
    // {
    //     if (sub > 50)
    //     {
    //         ret = true;
    //     }
    // }
    // else
    // {
    //     int gap = -100;
    // }
    if (voltage >= 1700)
    {
        if (sub > -300)
        {
            ret = true;
        }
    }

    last_voltage = voltage;
    if (ret)
    {
        ESP_LOGI(TAG, "trigger success");
    }
    return ret;
}
